package com.kang.c0c.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Hashtable;

/**
 *
 * Support for an abstract context, modelled loosely after ThreadLocal
 * but using a user-provided context instead of the current thread.
 *
 * Within the compiler, a single Context is used for each invocation of
 * the compiler.  The context is then used to ensure a single copy of
 * each compiler phase exists per compiler invocation.
 *
 * <p>Typical usage pattern is:
 * <pre>
 * public class Phase {
 *     private static final Context.Key<Phase> phaseKey = new Context.Key<Phase>();
 *
 *     public static Phase instance(Context context) {
 *	   Phase instance = context.get(phaseKey);
 *	   if (instance == null)
 *	       instance = new Phase(context);
 *	   return instance;
 *     }
 *
 *     protected Phase(Context context) {
 *	   context.put(thaseKey, this);
 *	   // other intitialization follows...
 *     }
 * }
 * </pre>
 * 
 * 这是一个神奇的类，它用Hashtable存储了所有在编译器进行编译阶段的整个全局范围内所需要的类的句柄
 * 借鉴自GJC源代码，并且在其代码的基础上增加了源程序缓冲区buf的存储
 *  
 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
public class Context {
	
	public static class Key{
		public Key(){
			super();
		}
	}
	
	private Hashtable<Key,Object> ht;
	//Context类是否初始化成功，主要针对loadBuf是否成功来判断的
	private boolean init;
	public String buf;
	
	public void put(Key key,Object data){
		if(ht.put(key,data) != null)
			throw new AssertionError("Duplicate context value");
	}
	
	public Object get(Key key){
		return ht.get(key);
	}
	public Context(File srcFile){
		super();
		ht = new Hashtable<Key,Object>();
		init = false;
		buf = "";
		loadBuf(srcFile);
	}
	
	public void clear(){
		ht.clear();
		buf = null;
	}
	
	/**
	 * 从文件中把源程序加载到缓冲区内
	 * @param srcFileName 源程序所在文件位置
	 */
	private void loadBuf(File file){
		init = false;
		try{
			if(file.exists() && file.isFile()){
				FileInputStream fin = new FileInputStream(file);	
				InputStreamReader reader = new InputStreamReader(fin);
				int bufsize = fin.available() + 1;
				char[] cbuf  = new char[bufsize];
				
				reader.read(cbuf,0,bufsize);
				reader.close();
				cbuf[cbuf.length-1] = '\0';
				
				buf = new String(cbuf);
				init = true;
			}else if(file.exists()){
				System.out.println(file + "is a directory");
			}else
				System.out.println(file + "is not exists or is a directory");			
		}catch(IOException ex){
			ex.printStackTrace();
		}
		
		if(buf.length() < 3)
			init = false;
	}
	
	public boolean isInitOkay() {
		return init;
	}
}
